package org.wx.herostory.services.encoder;

import com.google.protobuf.GeneratedMessageV3;
import lombok.extern.slf4j.Slf4j;
import org.wx.herostory.services.util.PackageUtil;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @program: my-java
 * @description: 动作命令处理工厂类
 * @author: Wang.xun
 * @create: 2021-03-01 22:03
 **/
@Slf4j
public class CmdHandlerFactory {
    /**
     * 动作命令类模型和处理类的字典
     */
    static private final Map<Class<?>,ICmdHandler<? extends GeneratedMessageV3>> _handlerMap = new HashMap<>();

    private CmdHandlerFactory() {
    }

    /**
     * 初始化对应关系
     */
    static public void init(){
        log.info("==== 完成命令与处理器的关联 ====");
        final String packageName = CmdHandlerFactory.class.getPackage().getName();
        /**
         列表指定包中的所有子类
         *
         * @param packageName 包名称
         * @param recursive   是否递归查找
         * @param superClazz  父类的类型
         * @return 子类集合
         */

        Set<Class<?>> clazzSet = PackageUtil.listSubClazz(packageName, true, ICmdHandler.class);

        for (Class<?> handlerClazz : clazzSet) {
            if (null == handlerClazz ||
                    0 != (handlerClazz.getModifiers() & Modifier.ABSTRACT)) {
                continue;
            }
            // 获取所有的方法
            Method[] methods = handlerClazz.getDeclaredMethods();
            // 消息类型
            Class<?> cmdClazz = null;
            for (Method method : methods) {
                if (null == method ||
                        !method.getName().equals("handle")) {
                    continue;
                }
                Class<?>[] parameterTypes = method.getParameterTypes();
                if (parameterTypes.length < 2 ||
                        parameterTypes[1] == GeneratedMessageV3.class ||
                        !GeneratedMessageV3.class.isAssignableFrom(parameterTypes[1])) {
                    continue;
                }
                // 动作命令的类模型
                cmdClazz = parameterTypes[1];
            }
            if(null == cmdClazz){
                continue;
            }
            try {
                ICmdHandler<?> handler = (ICmdHandler<?>)handlerClazz.newInstance();
                log.info(
                        "{} <==> {}",
                        cmdClazz.getName(),
                        handlerClazz.getName()
                );
                _handlerMap.put(cmdClazz, handler);
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 根据动作命令的类模型 ，获取动作处理类
     * @param clazz
     * @return
     */
    static public ICmdHandler<? extends GeneratedMessageV3> create(Class<?> clazz){
        if(null == clazz){
            return null;
        }
        return _handlerMap.get(clazz);
    }

}
